package com.xiaoq.order.endpoint;

import com.alibaba.dubbo.config.annotation.Reference;
import com.alibaba.fastjson.JSON;
import com.alipay.api.AlipayApiException;
import com.alipay.api.AlipayClient;
import com.alipay.api.DefaultAlipayClient;
import com.alipay.api.domain.AlipayTradeAppPayModel;
import com.alipay.api.internal.util.AlipaySignature;
import com.alipay.api.request.AlipayTradeAppPayRequest;
import com.alipay.api.response.AlipayTradeAppPayResponse;
import com.google.common.util.concurrent.RateLimiter;
import com.mongodb.DuplicateKeyException;
import com.xiaoq.apis.interpreter.IInterpreterApi;
import com.xiaoq.apis.interpreter.Interpreter4OrderVo;
import com.xiaoq.apis.user.IPushMessageApi;
import com.xiaoq.coms.GenericDataResponse;
import com.xiaoq.coms.GenericResponse;
import com.xiaoq.coms.util.ConstantUtil;
import com.xiaoq.coms.util.IdGenerator;
import com.xiaoq.coms.util.NetUtil;
import com.xiaoq.distribution.entity.TicketOrderItemEntity;
import com.xiaoq.distribution.service.ITicketOrderItemService;
import com.xiaoq.order.entity.PayState;
import com.xiaoq.order.entity.ShopOrderEntity;
import com.xiaoq.order.entity.ShoppingItem;
import com.xiaoq.order.service.IShopOrderService;
import com.xiaoq.order.thirdpayinfo.tencent.WxPayNotifyReturn;
import com.xiaoq.order.thirdpayinfo.tencent.XmlUtils;
import com.xiaoq.order.thirdpayinfo.tencent.common.RandomStringGenerator;
import com.xiaoq.order.thirdpayinfo.tencent.common.Signature;
import com.xiaoq.order.thirdpayinfo.tencent.common.XMLParser;
import com.xiaoq.order.thirdpayinfo.tencent.protocol.unifiedorder_protocol.UnifiedOrderReqData;
import com.xiaoq.order.thirdpayinfo.tencent.service.UnifiedOrderService;
import com.xiaoq.order.vo.GoPayVo;
import com.xiaoq.order.vo.PaySignVo;
import com.xiaoq.order.vo.WxH5ReturnVo;
import com.xiaoq.shop.entity.*;
import com.xiaoq.shop.service.IPayConfigService;
import com.xiaoq.shop.service.IShopPayTypeService;
import com.xiaoq.shop.service.IUserCouponService;
import com.xiaoq.sms.SendSMSUtil;

import io.swagger.annotations.*;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.UnsupportedEncodingException;
import java.text.SimpleDateFormat;
import java.util.*;

@RestController
@RequestMapping(value = "/api/v1/pay")
@Api(tags={"调起支付相关Api"})
class PayEndpoint2C {

    private static final Logger LOGGER = LoggerFactory.getLogger(PayEndpoint2C.class);

    @Autowired
    private IdGenerator idGenerator;

    private static final String ALIPAY_APP_ID = "2018010401568966";
//
//    //"填写您的pkcs8的私钥"
    private static final String ALIPAY_APP_PRIVATE_KEY = "MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQCGS4yDBoM8mRyIEE+IMPBEItCHaCpFQlqeJG85/iDMReuTMu9pT8U8xnHasYRgQsMW9Kva2PkQxYZpKzL75auVlo9PetNm+MWhVOzknyEMM8YpmM76bzGa+bEU7hzS3Pq9dQFOUwsj3UeiB5rdtHCHeOHy98UOzSzjNEiIwL3aiJAfqDqmWrR0UynYAsFOFUsWai7QC3U8KSrvbDCUjjtaXkPJ18xxYNQHR08LLazmUCbEd7RcDvvY3lEHmenMn0CQ4g4Kwn4LPHN4oXtTEDZUSGVGq0wzPD7JwbobYtGSr2297pQXM43F7ffS6z49oTysN3OGbdZ+X6xVE6cZJz6rAgMBAAECggEAXNx+w9dMBioFjZxhslXMvgCo2wjPOecBDBs7gglUmou6sqVk4RhU1YqPDd70Hy/rAMOc1g50YwGCyNQjRAVzGVPrstTGu4xH9B/qUsgqLOrcGsVcUdVzoqsHpOZlrfU5uKnghk1sBZesQcEqeCWeLj8LVlu3ul1rrYvooA9O+H20rcUzbn+erlrCfKS+vDgywZGvme9cmofa8XNWI7eE7G+TXdAZqA9legggAX/IQgeiCpo6UeuT0mgxWH4m69P23IBW/GB0NLasFnGbcVesXmWCPBPwsyharpgTHF3WFfkb59Cj8E9zSYImPPtMZCU9/cmJm6zKy+kBOMZ311ZkAQKBgQDWdhb/jWFrT9X8OhcLNdZ82u0AvYO5OG9JeyuvJXc+cwQ+9wvi9qbCxTd9sk4JkQAnLDOcqmmI1y8upYkLhlybduGHk9KJc/sIBnGk3w8Tqbt9I+UuNoFsflVLf8xq/1wOYVf+EkD5KulzZccfylYqDmpCs0m1Dv/No1bT+GDIqwKBgQCgTnnxs1ilpYdb11TIRhDFcZZ+GvEh1w/P4Mfh/89qeUsMw4wHiBv2kzDQXFZyC8R+XtSDF/ruy5abepSEn5n1hmyJ8L2Ymw7d+aGa/yhtLtpXS58bEl2RLvb9Mx/vxq+msXZ46OohuFtIfRuo/17Ji5MWaf94kYB1cn9r1d9iAQKBgE1EZqzUB1Fehj5Fv5+uWgTJ67HkldzZ1F6pHegQm5HIZrM41vOC4joyS/fhkfQoZeG3LzE2xKckwD8SLPoWAq+QeVkbjTMwsjUF/VPlec0fzgkcMaogwSiRq7Fz7fZu4n/b2pQTh40+RLXq6X8uqzSj1O0LI3c0XD1+p/3e8x/ZAoGAHcQUno2nszJWPPZx1rIz4QWjZQ0Jozf0xqu9UbiXQfT9u4P/11Itpw5TrQzIPGr09GYVXbYxMO/6qioLs8iS5OUt+DsMaW65RvxYRpiEYCmn/zeadoNlflTTJda9Yl9pNDGVhwPwnYxG3uHkJfAtII1bJXlPJ4sU6Dn3cQWIcgECgYEAnIiYZ6lGMB5j8ukMZsZ4iLdXbWlNtOXShZSBTGDkJ+njM3LatAUlNBsN5Fxh6FOagssEkGqLXygFoAHhISqThmj2KoMPxYXa4h3zAw55CqD24+tFgcoiqhziUHySubvqmvpO1J81LN+bH3NVL6eC5VW0syW7MEXHIMVnuXqo4/8=";
//
//    //"填写您的吧支付宝公钥" https://openhome.alipay.com/platform/keyManage.htm
    private static final String ALIPAY_PUBLIC_KEY = "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAhOzESlL+tvYlTlfVaGz/zJMYIqbuIRwO8pLDrZa0N0B8zp9s5s7AG9poxcJcV6ZA3jaE5WVvVgwJOe8MUdnhIITPhfe0T9eLPp/Z2XRc5jnMuqs9ujizOjeuOxDAzB26xJlmrNASH958ShN5EZCirMdzoYK4hOEOwtPy7oqWr9RDzzQwIST9hH/4xQD2HkzqQnWNr6PCwFv1xA4/Q2ndeEDAMI6NbnexZYiXQYRVBvwNSJnF3eXApAVMPHnL6QWyFnhG9xPsc2WPLLQxKp5GMPGukHVYEC5jqCNGi/07FGkbfCyrOJYh269+uZjG13car/neuc0N5r+Lvg/FvRRFLwIDAQAB";
    //签名方式
    private static final String ALIPAY_SIGN_TYPE = "RSA2";
    //编码格式
    private static final String CHARSET = "utf-8";
    //正式环境支付宝网关，如果是沙箱环境需更改成https://openapi.alipaydev.com/gateway.do
    private static final String url="https://openapi.alipay.com/gateway.do";
    private static final class PaySignResponse extends GenericDataResponse<PaySignVo> {}
    private static final class WxH5ReturnResponse extends GenericDataResponse<WxH5ReturnVo> {}


    @Autowired
    private IShopOrderService orderService;

    @Autowired
    private IUserCouponService userCouponService;

    @Autowired
    private IPayConfigService payConfigService;

    @Reference(interfaceClass=IInterpreterApi.class, check=false, version="1.0.0")
    private IInterpreterApi interpreterApi;

    @Reference(interfaceClass=IPushMessageApi.class, check=false, version="1.0.0")
    private IPushMessageApi pushMessageApi;

    @Autowired
    private SendSMSUtil sendSMSUtil;

    @Autowired
    private IShopPayTypeService shopPayTypeService;

    @Autowired
    private ITicketOrderItemService ticketOrderItemService;

    @ApiOperation(value="提交订单，生成(支付宝)sign", notes="提交订单，生成sign")
    @ApiResponses({
            @ApiResponse(code = 200, response = PaySignResponse.class, message = "提交订单，生成sign")
    })
    @PostMapping(value = "/ali/sign", produces ={MediaType.APPLICATION_JSON_UTF8_VALUE})
    public ResponseEntity<?> aliSign(@RequestBody GoPayVo payVo, HttpServletRequest httpServletRequest) throws AlipayApiException, UnsupportedEncodingException {

        String userId = (String) httpServletRequest.getAttribute("userId");
        if(StringUtils.isBlank(userId)){
            return GenericResponse.ng("该用户未登录");
        }

        if(payVo==null || StringUtils.isBlank(payVo.getOrderNo())){
            return GenericResponse.ng("RequestBody 不能为空");
        }

        ShopOrderEntity shopOrderEntity = orderService.getShopOrderByOrderId(payVo.getOrderNo());
        if(shopOrderEntity == null){
            return GenericResponse.ng("此订单不存在");
        }

        List<ShoppingItem> itemList = shopOrderEntity.getShoppingItems();
        if(CollectionUtils.isEmpty(itemList)){
            return GenericResponse.ng("此订单不存在单个items项");
        }
        ShoppingItem shoppingItem = itemList.get(0);
        String shopId = shopOrderEntity.getShopId();

        ShopPayTypeEntity shopPayTypeEntity = shopPayTypeService.getByShopId(shopId);
        if(shopPayTypeEntity == null){
            return GenericResponse.ng("此商户未设置支付方式");
        }

        Boolean isPayTest = shopPayTypeEntity.getPayTest();

        List<String> payTypes = shopPayTypeEntity.getPayMethods();
        if(CollectionUtils.isEmpty(payTypes) || (!payTypes.contains("" + ConstantUtil.PAY_TYPE_ALI_PAY))){
            return GenericResponse.ng("此商户不支持支付宝支付");
        }

        ALiPayConfigEntity payConfigEntity = payConfigService.getALiPayConfigByShopId(shopId);
        if(payConfigEntity==null || StringUtils.isEmpty(payConfigEntity.getId())){
            LOGGER.error("此商户暂未开通支付宝支付 " + shopOrderEntity);
            return GenericResponse.ng("此商户暂未开通支付宝支付");
        }

        if(StringUtils.isBlank(payConfigEntity.getaLiPayAppId())){
            return GenericResponse.ng("支付宝 APPID 未指定");
        }
        if(StringUtils.isBlank(payConfigEntity.getaLiPayAppPrivateKey())){
            return GenericResponse.ng("支付宝的pkcs8的私钥未指定");
        }
        if(StringUtils.isBlank(payConfigEntity.getaLiPayPublicKey())){
            return GenericResponse.ng("支付宝公钥未指定");
        }
        if(StringUtils.isBlank(payConfigEntity.getaLiPaySignType())){
            return GenericResponse.ng("签名方式未指定");
        }

        //实例化客户端(线程安全## https://docs.open.alipay.com/54)
        AlipayClient alipayClient = new DefaultAlipayClient(url,
                payConfigEntity.getaLiPayAppId(),
                payConfigEntity.getaLiPayAppPrivateKey(),
                "json",
                CHARSET,
                payConfigEntity.getaLiPayPublicKey(),
                ALIPAY_SIGN_TYPE);

        //实例化具体API对应的request类,类名称和接口名称对应,当前调用接口名称：alipay.trade.app.pay
        AlipayTradeAppPayRequest request = new AlipayTradeAppPayRequest();
        //SDK已经封装掉了公共参数，这里只需要传入业务参数。以下方法为sdk的model入参方式(model和biz_content同时存在的情况下取biz_content)。
        AlipayTradeAppPayModel model = new AlipayTradeAppPayModel();
        model.setBody(shoppingItem.getSpuName());
        model.setSubject(shoppingItem.getSpuName());
        //请保证OutTradeNo值每次保证唯一
        model.setOutTradeNo(shopOrderEntity.getShopOrderId());
        model.setTimeoutExpress("30m");
        model.setTotalAmount(shopOrderEntity.getTotalAmount() + "");

        if(isPayTest!=null && isPayTest){
            model.setTotalAmount("0.01");
        }

        model.setProductCode("QUICK_MSECURITY_PAY");
        request.setBizModel(model);
        ///result/{orderId}
        request.setNotifyUrl("https://order.xiaoq.online/api/v1/pay/result/notify");

        try {
            //这里和普通的接口调用不同，使用的是sdkExecute
            AlipayTradeAppPayResponse response = alipayClient.sdkExecute(request);
            //System.out.println(response.getBody());//就是orderString 可以直接给客户端请求，无需再做处理。

            PaySignVo paySignVo = new PaySignVo();
            paySignVo.setSign(response.getBody());
            return PaySignResponse.okWithData(paySignVo);
        } catch (AlipayApiException e) {
            LOGGER.error("AlipayApiException: " + e.getMessage(), e);
        }catch (Exception e){
            LOGGER.error(e.getMessage(), e);
        }

       return PaySignResponse.ng("支付宝签名错误");
    }

    @ApiOperation(value="提交订单，生成(支付宝)sign", notes="提交订单，生成sign")
    @ApiResponses({
            @ApiResponse(code = 200, response = PaySignResponse.class, message = "提交订单，生成sign")
    })
    @PostMapping(value = "/ali/sign/test", produces ={MediaType.APPLICATION_JSON_UTF8_VALUE})
    public ResponseEntity<?> aliSignTest(@RequestBody GoPayVo payVo, HttpServletRequest httpServletRequest) throws AlipayApiException, UnsupportedEncodingException {

        String userId = (String) httpServletRequest.getAttribute("userId");
        if(StringUtils.isBlank(userId)){
            return GenericResponse.ng("该用户未登录");
        }

        if(payVo==null || StringUtils.isBlank(payVo.getOrderNo())){
            return GenericResponse.ng("RequestBody 不能为空");
        }

        ShopOrderEntity shopOrderEntity = orderService.getShopOrderByOrderId(payVo.getOrderNo());
        if(shopOrderEntity == null){
            return GenericResponse.ng("此订单不存在");
        }

        List<ShoppingItem> itemList = shopOrderEntity.getShoppingItems();
        if(CollectionUtils.isEmpty(itemList)){
            return GenericResponse.ng("此订单不存在单个items项");
        }
        ShoppingItem shoppingItem = itemList.get(0);

        //实例化具体API对应的request类,类名称和接口名称对应,当前调用接口名称：alipay.trade.app.pay
        AlipayTradeAppPayRequest request = new AlipayTradeAppPayRequest();
        //SDK已经封装掉了公共参数，这里只需要传入业务参数。以下方法为sdk的model入参方式(model和biz_content同时存在的情况下取biz_content)。
        AlipayTradeAppPayModel model = new AlipayTradeAppPayModel();
        model.setBody(shoppingItem.getSpuName());
        model.setSubject(shoppingItem.getSpuName());
        //请保证OutTradeNo值每次保证唯一
        model.setOutTradeNo(shopOrderEntity.getShopOrderId());
        model.setTimeoutExpress("30m");
        //model.setTotalAmount(shopOrderEntity.getTotalAmount() + "");
        model.setTotalAmount("0.01");
        model.setProductCode("QUICK_MSECURITY_PAY");
        request.setBizModel(model);
        ///result/{orderId}
        request.setNotifyUrl("https://order.xiaoq.online/api/v1/pay/result/notify");

        AlipayClient alipayClient = new DefaultAlipayClient(url,
                ALIPAY_APP_ID,
                ALIPAY_APP_PRIVATE_KEY,
                "json",
                CHARSET,
                ALIPAY_PUBLIC_KEY,
                ALIPAY_SIGN_TYPE);

        try {
            //这里和普通的接口调用不同，使用的是sdkExecute
            AlipayTradeAppPayResponse response = alipayClient.sdkExecute(request);
            //System.out.println(response.getBody());//就是orderString 可以直接给客户端请求，无需再做处理。

            PaySignVo paySignVo = new PaySignVo();
            paySignVo.setSign(response.getBody());
            return PaySignResponse.okWithData(paySignVo);
        } catch (AlipayApiException e) {
            e.printStackTrace();
        }

        return PaySignResponse.ng("签名错误");
    }


    @ApiOperation(value="支付宝的回调", notes="支付宝的回调")
    @ApiResponses({
            @ApiResponse(code = 200, response = PaySignResponse.class, message = "支付宝的回调")
    })
    @RequestMapping(value = {"/result/notify"}, method = {RequestMethod.POST})
    @ResponseBody
    public String getPayNotify(HttpServletRequest request) throws Exception {
        Map<String, String> params = new HashMap<>();
        Map requestParams = request.getParameterMap();

        for (Iterator iter = requestParams.keySet().iterator(); iter.hasNext(); ) {
            String name = (String) iter.next();
            String[] values = (String[]) requestParams.get(name);
            String valueStr = "";
            for (int i = 0; i < values.length; i++) {
                valueStr = (i == values.length - 1) ? valueStr + values[i] : valueStr + values[i] + ",";
            }
            //乱码解决，这段代码在出现乱码时使用。如果mysign和sign不相等也可以使用这段代码转化
            //valueStr = new String(valueStr.getBytes("ISO-8859-1"), "gbk");
            params.put(name, valueStr);
        }

        //获取支付宝的通知返回参数，可参考技术文档中页面跳转同步通知参数列表(以下仅供参考)//
        //商户订单号
        String out_trade_no = new String(request.getParameter("out_trade_no").getBytes("ISO-8859-1"), "UTF-8");

        //支付宝交易号
        String trade_no = new String(request.getParameter("trade_no").getBytes("ISO-8859-1"), "UTF-8");

        //交易状态
        String trade_status = new String(request.getParameter("trade_status").getBytes("ISO-8859-1"), "UTF-8");

        //异步通知ID
        String notify_id = request.getParameter("notify_id");

        //交易状态
        String total_amount = new String(request.getParameter("total_amount").getBytes("ISO-8859-1"), "UTF-8");

        String queryString = request.getQueryString();
        LOGGER.error("**********************************");
        LOGGER.error("params: " + params);
        LOGGER.error("**********************************");

        //sign
        //String sign = request.getParameter("sign");
        if (AlipaySignature.rsaCheckV1(params, ALIPAY_PUBLIC_KEY, CHARSET, ALIPAY_SIGN_TYPE)){//使用支付宝公钥验签
            if (trade_status.equals("TRADE_FINISHED") || trade_status.equals("TRADE_SUCCESS")) {
                String orderId = out_trade_no;
                //业务处理
                LOGGER.error("*****************业务处理*****************");
                ShopOrderEntity shopOrderEntity = orderService.getShopOrderByOrderId(orderId);
                if(shopOrderEntity!=null && shopOrderEntity.getPaidTime()==null){
                    ShopOrderEntity updateShopOrder = new ShopOrderEntity();
                    updateShopOrder.setPaidTime(System.currentTimeMillis());
                    updateShopOrder.setPayState(PayState.PAID.value());
                    updateShopOrder.setShopOrderId(orderId);
                    updateShopOrder.setNote("支付宝支付");
                    //设置支付状态
                    //见ConstantUtil.INTERPRETER_STATUS_SERVICE_NOT_APPOINT  或 ConstantUtil.ORDER_TICKET_STATUS_HAVE_PAID
                    updateShopOrder.setOrderState(ConstantUtil.INTERPRETER_STATUS_SERVICE_NOT_APPOINT);
                    updateShopOrder.setRealPayMoney(Double.valueOf(total_amount));
                    updateShopOrder.setPayType(ConstantUtil.PAY_TYPE_ALI_PAY); //支付宝支付

                    LOGGER.error("支付宝支付测试..userId: " + shopOrderEntity.getUserId() + ", orderId: " + orderId);

                    boolean updateOrderFlag = orderService.updateShopOrderByOrderId(updateShopOrder);

                    TicketOrderItemEntity updateOrderItem = new TicketOrderItemEntity();
                    updateOrderItem.setShopOrderId(orderId);
                    updateOrderItem.setOrderState(ConstantUtil.ORDER_TICKET_STATUS_HAVE_PAID);
                    updateOrderItem.setPayState(PayState.PAID.value());
                    ticketOrderItemService.updateByOrderId(updateOrderItem);

                    String interpreterId = shopOrderEntity.getInterpreterId();

                    String shopId = shopOrderEntity.getShopId();
                    if(StringUtils.isNotBlank(interpreterId)){
                        Interpreter4OrderVo interpreter4OrderVo = interpreterApi.getInterByInterId(interpreterId);
                        if(interpreter4OrderVo != null){
                            if(interpreter4OrderVo.getStatus() != null){
                                try {
                                    //修改讲解员状态为 服务中
                                    boolean interFlag = interpreterApi.updateInter2Serving(interpreterId, shopId);
                                    if(!interFlag){
                                        LOGGER.error("修改讲解员状态失败，orderId：" + shopOrderEntity.getShopOrderId() + ", userId: " + shopOrderEntity.getUserId());
                                    }
                                }catch (Exception e){
                                    LOGGER.error("修改讲解员状态失败，orderId：" + shopOrderEntity.getShopOrderId() + ", userId: " + shopOrderEntity.getUserId(),e);
                                }

                                try {
                                    boolean calendarFlag = interpreterApi.updateInterCalendarStatus(shopOrderEntity.getShopOrderId(),
                                            ConstantUtil.INTERPRETER_STATUS_SERVICE_NOT_APPOINT);
                                    if(!calendarFlag){
                                        LOGGER.error("修改讲解员日历状态失败，orderId：" + shopOrderEntity + ", userId: " + shopOrderEntity.getUserId() );
                                    }
                                }catch (Exception e){
                                    LOGGER.error("修改讲解员日历状态失败，orderId：" + shopOrderEntity + ", userId: " + shopOrderEntity.getUserId(),e);
                                }

                                //小米推送,预约讲解员信息
                                sendInterpreterMessage(shopOrderEntity, interpreter4OrderVo);
                                sendSMS4InterpreterOrder(shopOrderEntity);
                            }else {
                                LOGGER.error("讲解员状态为null，orderId：" + shopOrderEntity + ", userId: " + shopOrderEntity.getUserId() );
                            }
                        }
                    }else {

                        sendSMS4TicketOrder(shopOrderEntity);
                        //小米推送,购票信息
                        sendTicketMessage(shopOrderEntity);
                    }

                    if(updateOrderFlag && StringUtils.isNotBlank(shopOrderEntity.getUserCounponId())
                            && StringUtils.isNotBlank(shopOrderEntity.getCouponCode())
                            && shopOrderEntity.getTotalMoneyOfUsedCoupons()!=null
                            && shopOrderEntity.getTotalMoneyOfUsedCoupons()>0){
                        //修改优惠券状态为已使用
                        userCouponService.updateUserCouponStatus(shopOrderEntity.getUserCounponId(),
                                shopOrderEntity.getUserId(),
                                UserCouponEntity.StateEnum.BEUSEED.value()
                        );
                    }
                }
            }

            return "success";
        } else{ //验证签名失败
            LOGGER.error("签名失败....");
            return "sign fail";
        }
    }


    @ApiOperation(value="testtesttest提交订单，生成(支付宝)sign", notes="test提交订单，生成sign")
    @ApiResponses({
            @ApiResponse(code = 200, response = PaySignResponse.class, message = "test提交订单，生成sign")
    })
    @PostMapping(value = "/ali/test", produces ={MediaType.APPLICATION_JSON_UTF8_VALUE})
    public ResponseEntity<?> aliSignTest(HttpServletRequest httpServletRequest) throws AlipayApiException, UnsupportedEncodingException {

        String userId = (String) httpServletRequest.getAttribute("userId");
        if(StringUtils.isBlank(userId)){
            return GenericResponse.ng("该用户未登录");
        }

        //实例化客户端
        AlipayClient alipayClient = new DefaultAlipayClient(url, ALIPAY_APP_ID, ALIPAY_APP_PRIVATE_KEY, "json", CHARSET, ALIPAY_PUBLIC_KEY,ALIPAY_SIGN_TYPE);
        //实例化具体API对应的request类,类名称和接口名称对应,当前调用接口名称：alipay.trade.app.pay
        AlipayTradeAppPayRequest request = new AlipayTradeAppPayRequest();
        //SDK已经封装掉了公共参数，这里只需要传入业务参数。以下方法为sdk的model入参方式(model和biz_content同时存在的情况下取biz_content)。
        AlipayTradeAppPayModel model = new AlipayTradeAppPayModel();
        model.setBody("我是测试数据");
        model.setSubject("App支付测试Java");
        //请保证OutTradeNo值每次保证唯一
        String num = idGenerator.nextId();
        model.setOutTradeNo("2018" + num + "ABA");
        model.setTimeoutExpress("30m");
        model.setTotalAmount("1");
        model.setProductCode("QUICK_MSECURITY_PAY");
        request.setBizModel(model);
        // https://sites.xiaoq.online/api/v1/pay/result/{orderId}
        request.setNotifyUrl("https://order.xiaoq.online/api/v1/pay/result/" + "2018" + num + "ABA");

        try {
            //这里和普通的接口调用不同，使用的是sdkExecute
            AlipayTradeAppPayResponse response = alipayClient.sdkExecute(request);
            System.out.println(response.getBody());//就是orderString 可以直接给客户端请求，无需再做处理。

            PaySignVo paySignVo = new PaySignVo();
            paySignVo.setSign(response.getBody());
            return PaySignResponse.okWithData(paySignVo);
        } catch (AlipayApiException e) {
            e.printStackTrace();
        }

        return PaySignResponse.ng("签名错误");
    }

    @ApiOperation(value="提交订单，生成(微信端)sign", notes="提交订单，生成(微信端)sign")
    @ApiResponses({
            @ApiResponse(code = 200, response = PaySignResponse.class, message = "提交订单，生成sign")
    })
    @PostMapping(value = "/wx/sign", produces ={MediaType.APPLICATION_JSON_UTF8_VALUE})
    public ResponseEntity<?> wxappPay(@RequestBody GoPayVo payVo, HttpServletRequest req,
                                      HttpServletResponse response) {
        try {

            String userId = (String) req.getAttribute("userId");
            if(StringUtils.isBlank(userId)){
                return GenericResponse.ng("该用户未登录");
            }

            if(payVo==null || StringUtils.isBlank(payVo.getOrderNo())){
                return GenericResponse.ng("RequestBody 不能为空");
            }

            ShopOrderEntity shopOrderEntity = orderService.getShopOrderByOrderId(payVo.getOrderNo());
            if(shopOrderEntity == null){
                return GenericResponse.ng("此订单不存在");
            }

            List<ShoppingItem> itemList = shopOrderEntity.getShoppingItems();
            if(CollectionUtils.isEmpty(itemList)){
                return GenericResponse.ng("此订单不存在单个items项");
            }
            ShoppingItem shoppingItem = itemList.get(0);
            String shopId = shopOrderEntity.getShopId();

            ShopPayTypeEntity shopPayTypeEntity = shopPayTypeService.getByShopId(shopId);
            if(shopPayTypeEntity == null){
                return GenericResponse.ng("此商户未设置支付方式");
            }
            Boolean isPayTest = shopPayTypeEntity.getPayTest();
            List<String> payTypes = shopPayTypeEntity.getPayMethods();
            if(CollectionUtils.isEmpty(payTypes) || (!payTypes.contains("" + ConstantUtil.PAY_TYPE_WEIXIN_PAY))){
                return GenericResponse.ng("此商户不支持微信支付");
            }

            WXPayConfigEntity wxPayConfig = payConfigService.getWXPayConfigByShopId(shopId, ConstantUtil.WX_PAY_TYPE_APP_PAY);

            if(wxPayConfig == null){
                return GenericResponse.ng("此店未设置微信支付信息");
            }

            if(StringUtils.isBlank(wxPayConfig.getAppId())){
                return GenericResponse.ng("微信没设置商户Id");
            }
            if(StringUtils.isBlank(wxPayConfig.getCertPassword())){
                return GenericResponse.ng("微信没设置证书密码");
            }
            if(StringUtils.isBlank(wxPayConfig.getCertPath())){
                return GenericResponse.ng("微信证书路径没指定");
            }
            if(StringUtils.isBlank(wxPayConfig.getMchId())){
                return GenericResponse.ng("商户ID没设置");
            }
            if(StringUtils.isBlank(wxPayConfig.getPayKey())){
                return GenericResponse.ng("商户支付密码没设置");
            }

            String appId = wxPayConfig.getAppId();
            String mchId = wxPayConfig.getMchId();
            String key = wxPayConfig.getPayKey(); //D:\weixin\cert\apiclient_cert.p12
            String certPath = wxPayConfig.getCertPath();
            String certPassword = wxPayConfig.getCertPassword();

            UnifiedOrderReqData order = new UnifiedOrderReqData();
            order.setAppid(appId);
            order.setMch_id(mchId);
            order.setNonce_str(RandomStringGenerator.getRandomStringByLength(30));
            order.setBody(shoppingItem.getSpuName());
            order.setOut_trade_no(shopOrderEntity.getShopOrderId());

            int value = (int)(shopOrderEntity.getTotalAmount() * 100);
            order.setTotal_fee(value);
            if(isPayTest!=null && isPayTest){
                order.setTotal_fee(1);
            }
            order.setSpbill_create_ip("8.8.8.8");
            order.setNotify_url("https://order.xiaoq.online/api/v1/pay/result/wxnotify");
            order.setTrade_type("NATIVE");
            order.setProduct_id(shoppingItem.getSkuCode());
            order.setSign(Signature.getSign(order.toMap(), key));

            UnifiedOrderService service = new UnifiedOrderService(certPath, certPassword);
            String result = service.request(order);
            Map<String, Object> map = XMLParser.getMapFromXML(result);
            String returnCode = (String) map.get("return_code");
            if (!StringUtils.isEmpty(returnCode)
                    && StringUtils.equals(returnCode, "SUCCESS")) {
                String url = (String) map.get("code_url");
                if (!StringUtils.isEmpty(url)) {
                    LOGGER.error("*****************************************" + url);
                }
            }

            if (!StringUtils.isEmpty(returnCode) && StringUtils.equals((String) map.get("return_msg"), "SUCCESS")
                    || StringUtils.equals((String) map.get("return_msg"), "OK")) {
                String prepay_id = (String) map.get("prepay_id");

                Map<String, Object> signMap = new HashMap<String, Object>();

                String nonceStr = RandomStringGenerator.getRandomStringByLength(30);
                long currentMillis = System.currentTimeMillis()/1000;
                signMap.put("appid", appId);
                signMap.put("partnerid", mchId);
                signMap.put("package", "Sign=WXPay");
                signMap.put("noncestr", nonceStr);
                signMap.put("timestamp", currentMillis);
                signMap.put("prepayid", prepay_id);
                String sign = Signature.getSign(signMap, key);

                PaySignVo paySignVo = new PaySignVo();
                paySignVo.setSign(sign);
                paySignVo.setPrepayId(prepay_id);
                paySignVo.setAppId(appId);
                paySignVo.setPackageName("Sign=WXPay");
                paySignVo.setPartnerId(mchId);
                paySignVo.setTimestamp(currentMillis);
                paySignVo.setNonceStr(nonceStr);

                return PaySignResponse.okWithData(paySignVo);
            } else {
                LOGGER.error("code is  " + returnCode);
                LOGGER.error("message is  " + (String) map.get("return_msg"));
                LOGGER.error("url is  " + (String) map.get("code_url"));
                LOGGER.error("err_code is  " + (String) map.get("err_code"));
                LOGGER.error("err_code_des  is  " + (String) map.get("err_code_des"));
            }

            return PaySignResponse.ng("微信签名错误...");
        } catch (Exception e) {
            LOGGER.error(e.getMessage(), e);
        }
        return PaySignResponse.ng("微信签名错误.");
    }

    @ApiOperation(value="提交订单，生成(微信端小程序)sign", notes="提交订单，生成(微信端小程序)sign")
    @ApiResponses({
            @ApiResponse(code = 200, response = PaySignResponse.class, message = "提交订单，生成微信端小程序sign")
    })
    @PostMapping(value = "/wxmini/sign", produces ={MediaType.APPLICATION_JSON_UTF8_VALUE})
    public ResponseEntity<?> wxMiniPay(@RequestBody GoPayVo payVo, HttpServletRequest req,
                                      HttpServletResponse response,
                                       @ApiParam(required = true, name = "openid", value = "用户openid")
                                           @RequestParam String openid) {
        try {

            String userId = (String) req.getAttribute("userId");
            if(StringUtils.isBlank(userId)){
                return GenericResponse.ng("该用户未登录");
            }

            if(payVo==null || StringUtils.isBlank(payVo.getOrderNo())){
                return GenericResponse.ng("RequestBody 不能为空");
            }
            if(StringUtils.isBlank(openid)){
                return GenericResponse.ng("未获取到用户的openid,请重新授权登录");
            }
            ShopOrderEntity shopOrderEntity = orderService.getShopOrderByOrderId(payVo.getOrderNo());
            if(shopOrderEntity == null){
                return GenericResponse.ng("此订单不存在");
            }

            List<ShoppingItem> itemList = shopOrderEntity.getShoppingItems();
            if(CollectionUtils.isEmpty(itemList)){
                return GenericResponse.ng("此订单不存在单个items项");
            }
            ShoppingItem shoppingItem = itemList.get(0);

            String shopId = shopOrderEntity.getShopId();

            ShopPayTypeEntity shopPayTypeEntity = shopPayTypeService.getByShopId(shopId);
            if(shopPayTypeEntity == null){
                return GenericResponse.ng("此商户未设置支付方式");
            }
            Boolean isPayTest = shopPayTypeEntity.getPayTest();
            List<String> payTypes = shopPayTypeEntity.getPayMethods();
            if(CollectionUtils.isEmpty(payTypes) || (!payTypes.contains("" + ConstantUtil.PAY_TYPE_WEIXIN_PAY))){
                return GenericResponse.ng("此商户不支持微信支付");
            }

            WXPayConfigEntity wxPayConfig = payConfigService.getWXPayConfigByShopId(shopId, ConstantUtil.WX_PAY_TYPE_MINI_PAY);

            if(wxPayConfig == null){
                return GenericResponse.ng("此店未设置微信支付信息");
            }

            if(StringUtils.isBlank(wxPayConfig.getAppId())){
                return GenericResponse.ng("微信没设置商户Id");
            }
            if(StringUtils.isBlank(wxPayConfig.getCertPassword())){
                return GenericResponse.ng("微信没设置证书密码");
            }
            if(StringUtils.isBlank(wxPayConfig.getCertPath())){
                return GenericResponse.ng("微信证书路径没指定");
            }
            if(StringUtils.isBlank(wxPayConfig.getMchId())){
                return GenericResponse.ng("商户ID没设置");
            }
            if(StringUtils.isBlank(wxPayConfig.getPayKey())){
                return GenericResponse.ng("商户支付密码没设置");
            }

            String appId = wxPayConfig.getAppId();
            String mchId = wxPayConfig.getMchId();
            String key = wxPayConfig.getPayKey(); //D:\weixin\cert\apiclient_cert.p12
            String certPath = wxPayConfig.getCertPath();
            String certPassword = wxPayConfig.getCertPassword();

            UnifiedOrderReqData order = new UnifiedOrderReqData();
            order.setOpenid(openid);
            order.setAppid(appId);
            order.setMch_id(mchId);
            order.setNonce_str(RandomStringGenerator.getRandomStringByLength(30));
            order.setBody(shoppingItem.getSpuName());
            order.setOut_trade_no(shopOrderEntity.getShopOrderId());

            int value = (int)(shopOrderEntity.getTotalAmount() * 100);
            order.setTotal_fee(value);
            if(isPayTest!=null && isPayTest){
                order.setTotal_fee(1);
            }

            order.setSpbill_create_ip("8.8.8.8");
            order.setNotify_url("https://order.xiaoq.online/api/v1/pay/result/mini/wxnotify");
            order.setTrade_type("JSAPI");
            order.setProduct_id(shoppingItem.getSkuCode());
            order.setSign(Signature.getSign(order.toMap(), key));

            UnifiedOrderService service = new UnifiedOrderService(certPath, certPassword);
            String result = service.request(order);
            Map<String, Object> map = XMLParser.getMapFromXML(result);
            String returnCode = (String) map.get("return_code");
            if (!StringUtils.isEmpty(returnCode)
                    && StringUtils.equals(returnCode, "SUCCESS")) {
                String url = (String) map.get("code_url");
                if (!StringUtils.isEmpty(url)) {
                    LOGGER.error("*****************************************" + url);
                }
            }

            if (!StringUtils.isEmpty(returnCode) && StringUtils.equals((String) map.get("return_msg"), "SUCCESS")
                    || StringUtils.equals((String) map.get("return_msg"), "OK")) {
                String prepay_id = (String) map.get("prepay_id");

                Map<String, Object> signMap = new HashMap<String, Object>();

                String nonceStr = RandomStringGenerator.getRandomStringByLength(30);
                long currentMillis = System.currentTimeMillis()/1000;
                signMap.put("appId", appId);
                signMap.put("timeStamp", currentMillis);
                signMap.put("nonceStr", nonceStr);
                //https://pay.weixin.qq.com/wiki/doc/api/wxa/wxa_api.php?chapter=7_7&index=3
                signMap.put("package", "prepay_id=" + prepay_id);
                signMap.put("signType", "MD5");

                String sign = Signature.getSign(signMap, key);

                PaySignVo paySignVo = new PaySignVo();
                paySignVo.setSign(sign);
                paySignVo.setPrepayId(prepay_id);
                paySignVo.setPackageName(prepay_id);
                paySignVo.setAppId(appId);
                paySignVo.setTimestamp(currentMillis);
                paySignVo.setNonceStr(nonceStr);

                return PaySignResponse.okWithData(paySignVo);
            } else {
                LOGGER.error("code is  " + returnCode);
                LOGGER.error("message is  " + (String) map.get("return_msg"));
                LOGGER.error("url is  " + (String) map.get("code_url"));
                LOGGER.error("err_code is  " + (String) map.get("err_code"));
                LOGGER.error("err_code_des  is  " + (String) map.get("err_code_des"));
            }

            return PaySignResponse.ng("微信签名错误...");
        } catch (Exception e) {
            LOGGER.error(e.getMessage(), e);
        }
        return PaySignResponse.ng("微信签名错误.");
    }

    /**
     * 微信 支付结果通知
     * @param req
     * @param response
     */
    @ApiOperation(value="微信 支付结果通知，返回给微信", notes="微信 支付结果通知,返回给微信")
    @ApiResponses({
            @ApiResponse(code = 200, response = String.class, message = "微信 支付结果通知")
    })
    @PostMapping(value = "/result/wxnotify", produces ={MediaType.APPLICATION_JSON_UTF8_VALUE})
    @ResponseBody
    public String giveMallMoneyResult(@RequestBody(required = false) String requestJson,
                                      HttpServletRequest req, HttpServletResponse response) {
        try {

            Map<String, Object> map = XMLParser.getMapFromXML(requestJson);

            LOGGER.error("********************map*******begin****************");
            LOGGER.error("map: " + map);
            LOGGER.error("********************map*******end****************");

            String returnCode = (String) map.get("return_code");
            if (!StringUtils.isEmpty(returnCode) && StringUtils.equals(returnCode, "SUCCESS")) {
                if (LOGGER.isDebugEnabled()) {
                    LOGGER.debug("out_trade_no  is " + map.get("out_trade_no"));
                    LOGGER.debug("pay over time is " + map.get("time_end"));
                }

                // 更新订单数据
                String priceStr = (String) map.get("total_fee");
                double price = Double.parseDouble(priceStr); // 单位为分
                String outTradeNo = (String) map.get("out_trade_no"); //orderId
                String payTimeStr = (String) map.get("time_end");

                ShopOrderEntity shopOrderEntity = orderService.getShopOrderByOrderId(outTradeNo);
                if(shopOrderEntity!=null && shopOrderEntity.getPaidTime()==null){
                    ShopOrderEntity updateShopOrder = new ShopOrderEntity();
                    updateShopOrder.setPaidTime(System.currentTimeMillis());
                    updateShopOrder.setPayState(PayState.PAID.value());
                    updateShopOrder.setShopOrderId(outTradeNo);
                    updateShopOrder.setNote("微信APP支付");
                    //见ConstantUtil.INTERPRETER_STATUS_SERVICE_NOT_APPOINT  或 ConstantUtil.ORDER_TICKET_STATUS_HAVE_PAID
                    updateShopOrder.setOrderState(ConstantUtil.INTERPRETER_STATUS_SERVICE_NOT_APPOINT);
                    updateShopOrder.setRealPayMoney(price/100.0);
                    updateShopOrder.setPayType(ConstantUtil.PAY_TYPE_WEIXIN_PAY);

                    LOGGER.error("微信支付测试..userId: " + shopOrderEntity.getUserId() + ", orderId: " + outTradeNo);

                    boolean updateOrderFlag = orderService.updateShopOrderByOrderId(updateShopOrder);
                    TicketOrderItemEntity updateOrderItem = new TicketOrderItemEntity();
                    updateOrderItem.setShopOrderId(outTradeNo);
                    updateOrderItem.setOrderState(ConstantUtil.ORDER_TICKET_STATUS_HAVE_PAID);
                    updateOrderItem.setPayState(PayState.PAID.value());
                    ticketOrderItemService.updateByOrderId(updateOrderItem);

                    //TODO 跟新讲解员的日历新信息
//                    if(updateOrderFlag && StringUtils.isNotBlank(shopOrderEntity.getInterpreterId())){
//                        InterCalendar4UpdateVo calendar4UpdateVo = new InterCalendar4UpdateVo();
//                        calendar4UpdateVo.setOrderId(orderId);
//                        calendar4UpdateVo.setStatus(1); //设置已支付
//                        interpreterApi.updateInterCalenarByOrderId(calendar4UpdateVo);
//                    }
                    String interpreterId = shopOrderEntity.getInterpreterId();

                    String shopId = shopOrderEntity.getShopId();
                    if(StringUtils.isNotBlank(interpreterId)){
                        Interpreter4OrderVo interpreter4OrderVo = interpreterApi.getInterByInterId(interpreterId);
                        if(interpreter4OrderVo != null){
                            if(interpreter4OrderVo.getStatus() != null){

                                try {
                                    //修改讲解员状态为 服务中
                                    boolean interFlag = interpreterApi.updateInter2Serving(interpreterId, shopId);
                                    if(!interFlag){
                                        LOGGER.error("修改讲解员状态失败，orderId：" + shopOrderEntity.getShopOrderId() + ", userId: " + shopOrderEntity.getUserId());
                                    }
                                }catch (Exception e){
                                    LOGGER.error("修改讲解员状态失败，orderId：" + shopOrderEntity.getShopOrderId() + ", userId: " + shopOrderEntity.getUserId(),e);
                                }

                                try {
                                    boolean calendarFlag = interpreterApi.updateInterCalendarStatus(shopOrderEntity.getShopOrderId(),
                                            ConstantUtil.INTERPRETER_STATUS_SERVICE_NOT_APPOINT);
                                    if(!calendarFlag){
                                        LOGGER.error("修改讲解员日历状态失败，orderId：" + shopOrderEntity + ", userId: " + shopOrderEntity.getUserId() );
                                    }
                                }catch (Exception e){
                                    LOGGER.error("修改讲解员日历状态失败，orderId：" + shopOrderEntity + ", userId: " + shopOrderEntity.getUserId(),e);
                                }

                                //小米推送,预约讲解员信息
                                sendInterpreterMessage(shopOrderEntity, interpreter4OrderVo);
                                sendSMS4InterpreterOrder(shopOrderEntity);
                            }else {
                                LOGGER.error("讲解员状态为null，orderId：" + shopOrderEntity + ", userId: " + shopOrderEntity.getUserId() );
                            }
                        }
                    }else {
                        //小米推送,购票信息
                        sendTicketMessage(shopOrderEntity);
                        sendSMS4TicketOrder(shopOrderEntity);
                    }

                    if(updateOrderFlag && StringUtils.isNotBlank(shopOrderEntity.getUserCounponId())
                            && StringUtils.isNotBlank(shopOrderEntity.getCouponCode())
                            && shopOrderEntity.getTotalMoneyOfUsedCoupons()!=null
                            && shopOrderEntity.getTotalMoneyOfUsedCoupons().intValue()>0){
                        //修改优惠券状态为已使用
                        userCouponService.updateUserCouponStatus(shopOrderEntity.getUserCounponId(),
                                shopOrderEntity.getUserId(),
                                UserCouponEntity.StateEnum.BEUSEED.value()
                        );
                    }

                    WxPayNotifyReturn returnResult = new WxPayNotifyReturn();
                    returnResult.setReturn_code("SUCCESS");
                    returnResult.setReturn_msg("OK");
                    return XmlUtils.toXml(returnResult);
                }
            }else {
                // 支付的通知接口有问题;
                LOGGER.error("**********************************************request is failed");
                WxPayNotifyReturn returnResult = new WxPayNotifyReturn();
                returnResult.setReturn_code("FAIL");
                returnResult.setReturn_msg("FAIL");
                return XmlUtils.toXml(returnResult);
            }
        } catch (Exception e) {
            LOGGER.error(e.getMessage(), e);
        }

        WxPayNotifyReturn returnResult = new WxPayNotifyReturn();
        returnResult.setReturn_code("FAIL");
        returnResult.setReturn_msg("FAIL");
        return XmlUtils.toXml(returnResult);
    }


    private void sendTicketMessage(ShopOrderEntity orderEntity){
        try {
            String content = "您已经成功预订" + orderEntity.getShopName() + "门票";
            new Thread(() -> {
                /**
                 *
                 * @param userId  C端的userId
                 * @param catalogueCode 板块code 1系统消息,2订单消息,3通知消息
                 * @param msgTitle  消息title
                 * @param msgContent  消息内容
                 * @param mesTarId  消息代表的具体内容Id 如果是票那就是票Id,讲解员Id等
                 * @param mesType  每种消息的分类 消息对象的具体类别（1系统消息，2,门票订单，3，讲解员订单，4，优惠劵）
                 * @param cornershopId 小店Id 可以传null
                 * @return
                 */
                boolean retFlag = pushMessageApi.sendMessage(orderEntity.getUserId(), String.valueOf(2), content, content, orderEntity.getShopOrderId(),String.valueOf(2), orderEntity.getShopId());
                if(!retFlag){
                    LOGGER.error("给购票的人发送订单消息--失败,订单Id: " + orderEntity.getShopOrderId());
                }else {
                    LOGGER.error("给购票的人发送订单消息--成功,订单Id: " + orderEntity.getShopOrderId());
                }
            }).start();
        }catch (Exception e){
            LOGGER.error(e.getMessage(), e);
            LOGGER.error("给购票的人发送订单消息失败,抛出异常,订单Id: " + orderEntity.getShopOrderId());
        }
    }

    /**
     * 微信（小程序）支付结果通知
     * @param req
     * @param response
     */
    @ApiOperation(value="微信（小程序）支付结果通知，返回给微信", notes="微信（小程序）支付结果通知,返回给微信")
    @ApiResponses({
            @ApiResponse(code = 200, response = String.class, message = "微信（小程序）支付结果通知")
    })
    @PostMapping(value = "/result/mini/wxnotify", produces ={MediaType.APPLICATION_JSON_UTF8_VALUE})
    @ResponseBody
    public String giveWxMiniMoneyResult(@RequestBody(required = false) String requestJson,
                                      HttpServletRequest req, HttpServletResponse response) {
        try {

            Map<String, Object> map = XMLParser.getMapFromXML(requestJson);

            LOGGER.error("********************map*******begin****************");
            LOGGER.error("map: " + map);
            LOGGER.error("********************map*******end****************");

            String returnCode = (String) map.get("return_code");
            if (!StringUtils.isEmpty(returnCode) && StringUtils.equals(returnCode, "SUCCESS")) {
                if (LOGGER.isDebugEnabled()) {
                    LOGGER.debug("out_trade_no  is " + map.get("out_trade_no"));
                    LOGGER.debug("pay over time is " + map.get("time_end"));
                }

                // 更新订单数据
                String priceStr = (String) map.get("total_fee");
                double price = Double.parseDouble(priceStr); // 单位为分
                String outTradeNo = (String) map.get("out_trade_no"); //orderId
//                String payTimeStr = (String) map.get("time_end");

                ShopOrderEntity shopOrderEntity = orderService.getShopOrderByOrderId(outTradeNo);
                if(shopOrderEntity!=null && shopOrderEntity.getPaidTime()==null){
                    ShopOrderEntity updateShopOrder = new ShopOrderEntity();
                    updateShopOrder.setPaidTime(System.currentTimeMillis());
                    updateShopOrder.setPayState(PayState.PAID.value());
                    updateShopOrder.setShopOrderId(outTradeNo);
                    updateShopOrder.setNote("微信小程序支付");
                    //见ConstantUtil.INTERPRETER_STATUS_SERVICE_NOT_APPOINT  或 ConstantUtil.ORDER_TICKET_STATUS_HAVE_PAID
                    updateShopOrder.setOrderState(ConstantUtil.INTERPRETER_STATUS_SERVICE_NOT_APPOINT);
                    updateShopOrder.setRealPayMoney(price/100.0);
                    updateShopOrder.setPayType(ConstantUtil.PAY_TYPE_WEIXIN_PAY);

                    LOGGER.error("微信支付测试..userId: " + shopOrderEntity.getUserId() + ", orderId: " + outTradeNo);

                    List<ShoppingItem> shoppingItems = shopOrderEntity.getShoppingItems();
                    ShoppingItem shoppingItem;
                    if(CollectionUtils.isNotEmpty(shoppingItems)){
                        shoppingItem = shoppingItems.get(0);
                    }else {
                        shoppingItem = new ShoppingItem();
                        shoppingItem.setTravelDate(0L);
                    }

                    boolean updateOrderFlag = orderService.updateShopOrderByOrderId(updateShopOrder);

                    TicketOrderItemEntity updateOrderItem = new TicketOrderItemEntity();
                    updateOrderItem.setShopOrderId(outTradeNo);
                    updateOrderItem.setOrderState(ConstantUtil.ORDER_TICKET_STATUS_HAVE_PAID);
                    updateOrderItem.setPayState(PayState.PAID.value());
                    ticketOrderItemService.updateByOrderId(updateOrderItem);

                    String interpreterId = shopOrderEntity.getInterpreterId();

                    String shopId = shopOrderEntity.getShopId();
                    if(StringUtils.isNotBlank(interpreterId)){
                        Interpreter4OrderVo interpreter4OrderVo = interpreterApi.getInterByInterId(interpreterId);
                        if(interpreter4OrderVo != null){
                            if(interpreter4OrderVo.getStatus() != null){

                                try {
                                    //修改讲解员状态为 服务中
                                    boolean interFlag = interpreterApi.updateInter2Serving(interpreterId, shopId);
                                    if(!interFlag){
                                        LOGGER.error("修改讲解员状态失败，orderId：" + shopOrderEntity.getShopOrderId() + ", userId: " + shopOrderEntity.getUserId());
                                    }
                                }catch (Exception e){
                                    LOGGER.error("修改讲解员状态失败，orderId：" + shopOrderEntity.getShopOrderId() + ", userId: " + shopOrderEntity.getUserId(),e);
                                }

                                try {
                                    boolean calendarFlag = interpreterApi.updateInterCalendarStatus(shopOrderEntity.getShopOrderId(),
                                            ConstantUtil.INTERPRETER_STATUS_SERVICE_NOT_APPOINT);
                                    if(!calendarFlag){
                                        LOGGER.error("修改讲解员日历状态失败，orderId：" + shopOrderEntity + ", userId: " + shopOrderEntity.getUserId() );
                                    }
                                }catch (Exception e){
                                    LOGGER.error("修改讲解员日历状态失败，orderId：" + shopOrderEntity + ", userId: " + shopOrderEntity.getUserId(),e);
                                }

                                //给预约讲解员的客户发短信
                                sendSMS4InterpreterOrder(shopOrderEntity);

                            }else {
                                LOGGER.error("讲解员状态为null，orderId：" + shopOrderEntity + ", userId: " + shopOrderEntity.getUserId() );
                            }
                        }
                    }else {
                        //生成电子票号
                        sendSMS4TicketOrder(shopOrderEntity);
                        //发送购票短信
                        sendSMS4TicketOrder(shopOrderEntity);
                    }

                    if(updateOrderFlag && StringUtils.isNotBlank(shopOrderEntity.getUserCounponId())
                            && StringUtils.isNotBlank(shopOrderEntity.getCouponCode())
                            && shopOrderEntity.getTotalMoneyOfUsedCoupons()!=null
                            && shopOrderEntity.getTotalMoneyOfUsedCoupons().intValue()>0){
                        //修改优惠券状态为已使用
                        userCouponService.updateUserCouponStatus(shopOrderEntity.getUserCounponId(),
                                shopOrderEntity.getUserId(),
                                UserCouponEntity.StateEnum.BEUSEED.value()
                        );
                    }

                    WxPayNotifyReturn returnResult = new WxPayNotifyReturn();
                    returnResult.setReturn_code("SUCCESS");
                    returnResult.setReturn_msg("OK");
                    return XmlUtils.toXml(returnResult);
                }
            }else {
                // 支付的通知接口有问题;
                LOGGER.error("**********************************************request is failed");
                WxPayNotifyReturn returnResult = new WxPayNotifyReturn();
                returnResult.setReturn_code("FAIL");
                returnResult.setReturn_msg("FAIL");
                return XmlUtils.toXml(returnResult);
            }
        } catch (Exception e) {
            LOGGER.error(e.getMessage(), e);
        }

        WxPayNotifyReturn returnResult = new WxPayNotifyReturn();
        returnResult.setReturn_code("FAIL");
        returnResult.setReturn_msg("FAIL");
        return XmlUtils.toXml(returnResult);
    }

    /**
     * 微信 支付结果通知
     * @param req
     * @param response
     */
    @ApiOperation(value="微信 支付结果通知，返回给微信（仅测试用）", notes="微信 支付结果通知,返回给微信")
    @ApiResponses({
            @ApiResponse(code = 200, response = String.class, message = "微信 支付结果通知")
    })
    @GetMapping(value = "/result/{orderId}", produces ={MediaType.APPLICATION_JSON_UTF8_VALUE})
    @ResponseBody
    public String giveMallMoneyResult(@RequestBody(required = false) String requestJson,
                                      HttpServletRequest req,
                                      @PathVariable @ApiParam(value="orderId", required=true) String orderId ,
                                      HttpServletResponse response) {
        try {

            if (LOGGER.isDebugEnabled()) {
                LOGGER.debug("**********************************************orderId************************ is "
                        + orderId);
            }

            if(StringUtils.isNotBlank(orderId)){
                ShopOrderEntity shopOrderEntity = orderService.getShopOrderByOrderId(orderId);
                if(shopOrderEntity!=null && shopOrderEntity.getPaidTime()==null){
                    ShopOrderEntity updateShopOrder = new ShopOrderEntity();
                    updateShopOrder.setPaidTime(System.currentTimeMillis());
                    updateShopOrder.setPayState(PayState.PAID.value());
                    updateShopOrder.setShopOrderId(orderId);
                    //见ConstantUtil.INTERPRETER_STATUS_SERVICE_NOT_APPOINT  或 ConstantUtil.ORDER_TICKET_STATUS_HAVE_PAID
                    updateShopOrder.setOrderState(ConstantUtil.INTERPRETER_STATUS_SERVICE_NOT_APPOINT);
                    updateShopOrder.setRealPayMoney(shopOrderEntity.getTotalAmount());
                    updateShopOrder.setPayType(ConstantUtil.PAY_TYPE_WEIXIN_PAY);

                    LOGGER.error("微信支付测试..userId: " + shopOrderEntity.getUserId() + ", orderId: " + shopOrderEntity.getShopOrderId());

                    boolean updateOrderFlag = orderService.updateShopOrderByOrderId(updateShopOrder);
                    //TODO 跟新讲解员的日历新信息
                    String interpreterId = shopOrderEntity.getInterpreterId();
                    TicketOrderItemEntity updateOrderItem = new TicketOrderItemEntity();
                    updateOrderItem.setShopOrderId(shopOrderEntity.getShopOrderId());
                    updateOrderItem.setOrderState(ConstantUtil.ORDER_TICKET_STATUS_HAVE_PAID);
                    updateOrderItem.setPayState(PayState.PAID.value());
                    ticketOrderItemService.updateByOrderId(updateOrderItem);

                    String shopId = shopOrderEntity.getShopId();
                    if(StringUtils.isNotBlank(interpreterId)){
                        Interpreter4OrderVo interpreter4OrderVo = interpreterApi.getInterByInterId(interpreterId);
                        if(interpreter4OrderVo != null){
                            if(interpreter4OrderVo.getStatus() != null){

                                try {
                                    //修改讲解员状态为 服务中
                                    boolean interFlag = interpreterApi.updateInter2Serving(interpreterId, shopId);
                                    if(!interFlag){
                                        LOGGER.error("修改讲解员状态失败，orderId：" + shopOrderEntity.getShopOrderId() + ", userId: " + shopOrderEntity.getUserId());
                                    }
                                }catch (Exception e){
                                    LOGGER.error("修改讲解员状态失败，orderId：" + shopOrderEntity.getShopOrderId() + ", userId: " + shopOrderEntity.getUserId(),e);
                                }

                                try {
                                    boolean calendarFlag = interpreterApi.updateInterCalendarStatus(shopOrderEntity.getShopOrderId(),
                                            ConstantUtil.INTERPRETER_STATUS_SERVICE_NOT_APPOINT);
                                    if(!calendarFlag){
                                        LOGGER.error("修改讲解员日历状态失败，orderId：" + shopOrderEntity + ", userId: " + shopOrderEntity.getUserId() );
                                    }
                                }catch (Exception e){
                                    LOGGER.error("修改讲解员日历状态失败，orderId：" + shopOrderEntity + ", userId: " + shopOrderEntity.getUserId(),e);
                                }

                                //小米推送,预约讲解员信息
                                sendInterpreterMessage(shopOrderEntity, interpreter4OrderVo);
                            }else {
                                LOGGER.error("讲解员状态为null，orderId：" + shopOrderEntity + ", userId: " + shopOrderEntity.getUserId() );
                            }
                        }
                    }else {
                        sendSMS4TicketOrder(shopOrderEntity);
                        //小米推送,购票信息
                        sendTicketMessage(shopOrderEntity);
                    }

                    if(updateOrderFlag && StringUtils.isNotBlank(shopOrderEntity.getUserCounponId())
                            && StringUtils.isNotBlank(shopOrderEntity.getCouponCode())
                            && shopOrderEntity.getTotalMoneyOfUsedCoupons()!=null
                            && shopOrderEntity.getTotalMoneyOfUsedCoupons()>0){
                        //修改优惠券状态为已使用
                        userCouponService.updateUserCouponStatus(shopOrderEntity.getUserCounponId(),
                                shopOrderEntity.getUserId(),
                                UserCouponEntity.StateEnum.BEUSEED.value()
                        );
                    }

                    WxPayNotifyReturn returnResult = new WxPayNotifyReturn();
                    returnResult.setReturn_code("SUCCESS");
                    returnResult.setReturn_msg("OK");
                    return JSON.toJSONString(returnResult);
                }
            }else {
                // 支付的通知接口有问题;
                LOGGER.error("**********************************************request is failed");
                WxPayNotifyReturn returnResult = new WxPayNotifyReturn();
                returnResult.setReturn_code("FAIL");
                returnResult.setReturn_msg("FAIL");
                return JSON.toJSONString(returnResult);
            }
        } catch (Exception e) {
            LOGGER.error(e.getMessage(), e);
        }

        WxPayNotifyReturn returnResult = new WxPayNotifyReturn();
        returnResult.setReturn_code("FAIL");
        returnResult.setReturn_msg("FAIL");
        return JSON.toJSONString(returnResult);
    }


    @PostMapping(value = "/wx/testsign", produces ={MediaType.APPLICATION_JSON_UTF8_VALUE})
    public ResponseEntity<?> test(@RequestBody GoPayVo payVo, HttpServletRequest req,
                                      HttpServletResponse response) {
        try {
            String nonce = "ls8o40lngs85pe9qvm3lccn2g4z9nk";
            String appId = "wx1f3ddeffce106844";
            String mchId = "1497234242";
            String key = "XiaoQtJ0lngs85pe9qvm3lccn2g4z9nk"; //
            String certPath = "D:\\weixin\\cert\\apiclient_cert.p12";
            String certPassword = "1497234242";

            UnifiedOrderReqData order = new UnifiedOrderReqData();
            order.setAppid(appId);
            order.setMch_id(mchId);
            order.setNonce_str(nonce);
            order.setBody("13241234");
            order.setOut_trade_no("234523sfgd1234f565");
            order.setTotal_fee(1);
            order.setSpbill_create_ip("8.8.8.8");
            order.setNotify_url("https://order.xiaoq.online/api/v1/pay/result/wxnotify");
            order.setTrade_type("NATIVE");
            order.setProduct_id("223453");
            order.setSign(Signature.getSign(order.toMap(), key));

            UnifiedOrderService service = new UnifiedOrderService(certPath, certPassword);
            String result = service.request(order);
            System.out.println(result);
            Map<String, Object> map = XMLParser.getMapFromXML(result);
            String returnCode = (String) map.get("return_code");
            if (!StringUtils.isEmpty(returnCode)
                    && StringUtils.equals(returnCode, "SUCCESS")) {
                String url = (String) map.get("code_url");
                if (!StringUtils.isEmpty(url)) {
                    System.out.println("*****************************************" + url);
                }
            }

            System.out.println("code is  " + returnCode);
            System.out.println("message is  " + (String) map.get("return_msg"));
            System.out.println("url is  " + (String) map.get("code_url"));
            System.out.println("err_code is  " + (String) map.get("err_code"));
            System.out.println("err_code_des  is  " + (String) map.get("err_code_des"));

            if (!StringUtils.isEmpty(returnCode) && StringUtils.equals((String) map.get("return_msg"), "SUCCESS")
                    || StringUtils.equals((String) map.get("return_msg"), "OK")) {
                String prepay_id = (String) map.get("prepay_id");

                Map<String, Object> signMap = new HashMap<String, Object>();

                String nonceStr = RandomStringGenerator.getRandomStringByLength(10);
                long currentMills = System.currentTimeMillis()/1000;
                signMap.put("appid", appId);
                signMap.put("partnerid", mchId);
                signMap.put("package", "Sign=WXPay");
                signMap.put("noncestr", nonceStr);
                signMap.put("timestamp", currentMills);
                signMap.put("prepayid", prepay_id);
                String sign = Signature.getSign(signMap, key);

                PaySignVo paySignVo = new PaySignVo();
                paySignVo.setSign(sign);
                paySignVo.setPrepayId(prepay_id);
                paySignVo.setAppId(appId);
                paySignVo.setPackageName("Sign=WXPay");
                paySignVo.setPartnerId(mchId);
                paySignVo.setTimestamp(currentMills);
                paySignVo.setNonceStr(nonceStr);

                return PaySignResponse.okWithData(paySignVo);
            } else {
                LOGGER.error("**********************************************request is failed");
            }

            return PaySignResponse.ng("微信签名错误...");
        } catch (Exception e) {
            LOGGER.error(e.getMessage(), e);
        }
        return PaySignResponse.ng("微信签名错误.");
    }


    private void sendInterpreterMessage(ShopOrderEntity orderEntity, Interpreter4OrderVo interpreter4OrderVo){
        try {
            String content = "您已经成功预订" + interpreter4OrderVo.getName() + "讲解员";
            new Thread(() -> {

                /**
                 * @param userId  C端的userId
                 * @param catalogueCode 板块code 1系统消息,2订单消息,3通知消息
                 * @param msgTitle  消息title
                 * @param msgContent  消息内容
                 * @param mesTarId  消息代表的具体内容Id 如果是票那就是票Id,讲解员Id等
                 * @param mesType  每种消息的分类 消息对象的具体类别（1系统消息，2,门票订单，3，讲解员订单，4，优惠劵）
                 * @param cornershopId 小店Id 可以传null
                 * @return
                 */
                boolean retFlag = pushMessageApi.sendMessage(orderEntity.getUserId(), String.valueOf(2), content, content,
                        orderEntity.getInterpreterId(),String.valueOf(3), orderEntity.getShopId());
                if(!retFlag){
                    LOGGER.error("给讲解员发送订单消息--失败,订单Id: " + orderEntity.getShopOrderId());
                }else {
                    LOGGER.error("给讲解员发送订单消息--成功,订单Id: " + orderEntity.getShopOrderId());
                }

            }).start();
        }catch (Exception e){
            LOGGER.error(e.getMessage(), e);
            LOGGER.error("给讲解员发送订单消息失败,抛出异常,订单Id: " + orderEntity.getShopOrderId());
        }
    }


    private void sendSMS4TicketOrder(ShopOrderEntity shopOrderEntity){
        new Thread(() -> {

            if(shopOrderEntity == null){
                return;
            }
            if(CollectionUtils.isEmpty(shopOrderEntity.getShoppingItems())){
                return;
            }

            try {
                ShoppingItem shoppingItem = shopOrderEntity.getShoppingItems().get(0);
                String userName = shopOrderEntity.getUserRealName(),
                        shopName = shopOrderEntity.getShopName(),
                        ticketName = shoppingItem.getSpuName(),
                        ticketNum = shoppingItem.getNumber() + "",
                        tourDate = new SimpleDateFormat("yyyy-MM-dd").format(new Date(shoppingItem.getTravelDate())),
                        orderNum = shopOrderEntity.getShopOrderId(),
                        teleNumber = shopOrderEntity.getCellphoneNumber();

                String msg = sendSMSUtil.sendSMS4TicketOrder(userName, shopName, ticketName, ticketNum, tourDate, orderNum, teleNumber);
                LOGGER.error(msg);
            }catch (Exception e){
                LOGGER.error(e.getMessage(), e);
            }
        }).start();
    }


    public void sendSMS4InterpreterOrder(ShopOrderEntity shopOrderEntity){
        new Thread(() -> {

            if(shopOrderEntity == null){
                return;
            }
            if(CollectionUtils.isEmpty(shopOrderEntity.getShoppingItems())){
                return;
            }

            try {
                String userName = shopOrderEntity.getUserRealName(),
                        shopName = shopOrderEntity.getShopName(),
                        tourDate = new SimpleDateFormat("yyyy-MM-dd").format(new Date(shopOrderEntity.getCreateTime())),
                        orderNum = shopOrderEntity.getShopOrderId(),
                        teleNumber = shopOrderEntity.getCellphoneNumber();

                String msg = sendSMSUtil.sendSMS4InterpreterOrder(userName, shopName, tourDate, orderNum, teleNumber);
                LOGGER.error(msg);
            }catch (Exception e){
                LOGGER.error(e.getMessage(), e);
            }
        }).start();
    }

    @ApiOperation(value="小米推送测试", notes="小米推送测试")
    @ApiResponses({
            @ApiResponse(code = 200, response = GenericResponse.class, message = "小米推送测试")
    })
    @GetMapping(value = "/push", produces = MediaType.APPLICATION_JSON_UTF8_VALUE)
    public ResponseEntity<?> push(HttpServletRequest request,

                                  @RequestParam(value = "userId", defaultValue = "")
                                  @ApiParam(value="给userId用户发小米推送(如果为空,则给此登录用户发小米推送)", required=false) String userId,

                                  @RequestParam(value = "catalogueCode", defaultValue = "")
                                  @ApiParam(value="板块code 1系统消息,2订单消息,3通知消息", required=true) String catalogueCode,

                                  @RequestParam(value = "msgTitle", defaultValue = "")
                                      @ApiParam(value="消息title", required=true) String msgTitle,

                                  @RequestParam(value = "msgContent", defaultValue = "")
                                      @ApiParam(value="消息内容", required=true) String msgContent,

                                  @RequestParam(value = "mesTarId", defaultValue = "")
                                      @ApiParam(value="消息代表的具体内容Id 如果是票那就是票Id,讲解员Id等", required=true) String mesTarId,

                                  @RequestParam(value = "mesType", defaultValue = "")
                                      @ApiParam(value="每种消息的分类 消息对象的具体类别（1系统消息，2,门票订单，3，讲解员订单，4，优惠劵）", required=true) String mesType,

                                  @RequestParam(value = "shopId", defaultValue = "")
                                      @ApiParam(value="小店Id 可以不传", required=false) String shopId,

                                  @RequestParam(value = "mesUrl", defaultValue = "")
                                      @ApiParam(value="图片的URL链接", required=false) String mesUrl,

                                  @RequestParam(value = "mutable_content", defaultValue = "")
                                      @ApiParam(value="是否是图片推送", required=false) boolean mutable_content) {

        if(StringUtils.isBlank(userId)){
            userId = (String) request.getAttribute("userId");
        }

        /**
         * @param userId  C端的userId
         * @param catalogueCode 板块code 1系统消息,2订单消息,3通知消息
         * @param msgTitle  消息title
         * @param msgContent  消息内容
         * @param mesTarId  消息代表的具体内容Id 如果是票那就是票Id,讲解员Id等
         * @param mesType  每种消息的分类 消息对象的具体类别（1系统消息，2,门票订单，3，讲解员订单，4，优惠劵）
         * @param cornershopId 小店Id 可以传null
         * @return
         */
        boolean retFlag = pushMessageApi.sendMessageWithImag(userId, catalogueCode, msgContent, msgContent, mesTarId,mesType, shopId, mesUrl, mutable_content);

        if(!retFlag){
            return GenericResponse.ng("发送失败.   ");
        }else {
            return GenericResponse.ok();
        }
    }


    public static void main_1(String[] args) {
        try {
            String nonce = "ls8o40lngs85pe9qvm3lccn2g4z9nk";
            String appId = "wx1f3ddeffce106844";
            String mchId = "1497234242";
            String key = "XiaoQtJ0lngs85pe9qvm3lccn2g4z9nk"; //
            String certPath = "D:\\weixin\\cert\\apiclient_cert.p12";
            String certPassword = "1497234242";

            UnifiedOrderReqData order = new UnifiedOrderReqData();
            order.setAppid(appId);
            order.setMch_id(mchId);
            order.setNonce_str(nonce);
            order.setBody("13241234");
            order.setOut_trade_no("2asf3sfgd1234f565asdasd");
            order.setTotal_fee(1);
            order.setSpbill_create_ip("1.202.219.75");
            order.setNotify_url("https://order.xiaoq.online/api/v1/pay/result/wxnotify");
            order.setTrade_type("MWEB");
            order.setProduct_id("223453");
            order.setScene_info("{\"h5_info\": {\"type\":\"IOS\",\"app_name\": \"小Q旅行\",\"bundle_id\": \"online.xiaoq\"}}");

            order.setSign(Signature.getSign(order.toMap(), key));

            UnifiedOrderService service = new UnifiedOrderService(certPath, certPassword);
            String result = service.request(order);
            System.out.println(result);
            Map<String, Object> map = XMLParser.getMapFromXML(result);
            String returnCode = (String) map.get("return_code");
            if (!StringUtils.isEmpty(returnCode)
                    && StringUtils.equals(returnCode, "SUCCESS")) {
                String url = (String) map.get("code_url");
                if (!StringUtils.isEmpty(url)) {
                    System.out.println("*****************************************" + url);
                }
            }

            System.out.println("******************************************");
            System.out.println("map: " + map);
            ;
            System.out.println("******************************************");

            System.out.println("code is  " + returnCode);
            System.out.println("message is  " + (String) map.get("return_msg"));
            System.out.println("url is  " + (String) map.get("code_url"));
            System.out.println("err_code is  " + (String) map.get("err_code"));
            System.out.println("err_code_des  is  " + (String) map.get("err_code_des"));
        }catch (Exception e){
            e.printStackTrace();
        }
    }

    public static void main(String[] args) {

        try {
            String nonce = "ls8o40lngs85pe9qvm3lccn2g4z9nk";
            String appId = "wx54d1da8c10bc5850";
            String mchId = "1498390562";
            String key = "h5wxdzt9i45wn6j8u3lmuirvcnk10h55"; //
            String certPath = "D:\\weixin\\cert-q2\\apiclient_cert.p12";
            String certPassword = "1498390562";

            UnifiedOrderReqData order = new UnifiedOrderReqData();
            order.setAppid(appId);
            order.setMch_id(mchId);
            order.setNonce_str(nonce);
            order.setBody("13241234");
            order.setOut_trade_no("1234567890");
            order.setTotal_fee(1);
            order.setSpbill_create_ip("1.202.219.75");
            order.setNotify_url("https://order.xiaoq.online/api/v1/pay/result/wxnotify");
            order.setTrade_type("MWEB");
            order.setProduct_id("223453");
            order.setScene_info("{\"h5_info\": {\"type\":\"IOS\",\"app_name\": \"小Q旅行\",\"bundle_id\": \"online.xiaoq\"}}");

            order.setSign(Signature.getSign(order.toMap(), key));

            UnifiedOrderService service = new UnifiedOrderService(certPath, certPassword);
            String result = service.request(order);
            System.out.println(result);
            Map<String, Object> map = XMLParser.getMapFromXML(result);
            String returnCode = (String) map.get("return_code");
            if (!StringUtils.isEmpty(returnCode)
                    && StringUtils.equals(returnCode, "SUCCESS")) {
                String url = (String) map.get("code_url");
                if (!StringUtils.isEmpty(url)) {
                    System.out.println("*****************************************" + url);
                }
            }

            System.out.println("******************************************");
            System.out.println("map: " + map);
            ;
            System.out.println("******************************************");

            System.out.println("code is  " + returnCode);
            System.out.println("message is  " + (String) map.get("return_msg"));
            System.out.println("url is  " + (String) map.get("code_url"));
            System.out.println("err_code is  " + (String) map.get("err_code"));
            System.out.println("err_code_des  is  " + (String) map.get("err_code_des"));
        }catch (Exception e){
            e.printStackTrace();
        }
    }

    @ApiOperation(value="提交订单，生成H5 (微信端)sign", notes="提交订单，生成H5(微信端)sign")
    @ApiResponses({
            @ApiResponse(code = 200, response = WxH5ReturnResponse.class, message = "提交订单，生成H5  sign")
    })
    @PostMapping(value = "/wx/h5sign", produces ={MediaType.APPLICATION_JSON_UTF8_VALUE})
    public ResponseEntity<?> wxH5Pay(@RequestBody GoPayVo payVo, HttpServletRequest req,
                                     HttpServletResponse response) {
        try {

            String ipAddr = NetUtil.getIpAddr(req);
            String tt = getIpAddr(req);

            LOGGER.error("************ipADDR*********" + ipAddr);
            LOGGER.error("************tt*********" + tt);

            String userId = (String) req.getAttribute("userId");
            if(StringUtils.isBlank(userId)){
                return GenericResponse.ng("该用户未登录");
            }

            if(payVo==null || StringUtils.isBlank(payVo.getOrderNo())){
                return GenericResponse.ng("RequestBody 不能为空");
            }

            if(StringUtils.isBlank(payVo.getAppType())){
                return GenericResponse.ng("手机类型不能为空");
            }

            ShopOrderEntity shopOrderEntity = orderService.getShopOrderByOrderId(payVo.getOrderNo());
            if(shopOrderEntity == null){
                return GenericResponse.ng("此订单不存在");
            }

            List<ShoppingItem> itemList = shopOrderEntity.getShoppingItems();
            if(CollectionUtils.isEmpty(itemList)){
                return GenericResponse.ng("此订单不存在单个items项");
            }
            ShoppingItem shoppingItem = itemList.get(0);
            String shopId = shopOrderEntity.getShopId();

            ShopPayTypeEntity shopPayTypeEntity = shopPayTypeService.getByShopId(shopId);
            if(shopPayTypeEntity == null){
                return GenericResponse.ng("此商户未设置支付方式");
            }
            Boolean isPayTest = shopPayTypeEntity.getPayTest();
            List<String> payTypes = shopPayTypeEntity.getPayMethods();
            if(CollectionUtils.isEmpty(payTypes) || (!payTypes.contains("" + ConstantUtil.PAY_TYPE_WEIXIN_PAY))){
                return GenericResponse.ng("此商户不支持微信支付");
            }

            WXPayConfigEntity wxPayConfig = payConfigService.getWXPayConfigByShopId(shopId, ConstantUtil.WX_PAY_TYPE_APP_PAY);

            if(wxPayConfig == null){
                return GenericResponse.ng("此店未设置微信支付信息");
            }

            if(StringUtils.isBlank(wxPayConfig.getAppId())){
                return GenericResponse.ng("微信没设置商户Id");
            }
            if(StringUtils.isBlank(wxPayConfig.getCertPassword())){
                return GenericResponse.ng("微信没设置证书密码");
            }
            if(StringUtils.isBlank(wxPayConfig.getCertPath())){
                return GenericResponse.ng("微信证书路径没指定");
            }
            if(StringUtils.isBlank(wxPayConfig.getMchId())){
                return GenericResponse.ng("商户ID没设置");
            }
            if(StringUtils.isBlank(wxPayConfig.getPayKey())){
                return GenericResponse.ng("商户支付密码没设置");
            }

            String appId = wxPayConfig.getAppId();
            String mchId = wxPayConfig.getMchId();
            String key = wxPayConfig.getPayKey(); //D:\weixin\cert\apiclient_cert.p12
            String certPath = wxPayConfig.getCertPath();
            String certPassword = wxPayConfig.getCertPassword();

            UnifiedOrderReqData order = new UnifiedOrderReqData();
            order.setAppid(appId);
            order.setMch_id(mchId);
            order.setNonce_str(RandomStringGenerator.getRandomStringByLength(30));
            order.setBody(shoppingItem.getSpuName());
            order.setOut_trade_no(shopOrderEntity.getShopOrderId());

            int value = (int)(shopOrderEntity.getTotalAmount() * 100);
            order.setTotal_fee(value);
            if(isPayTest!=null && isPayTest){
                order.setTotal_fee(1);
            }
            order.setSpbill_create_ip(ipAddr);
            order.setNotify_url("https://order.xiaoq.online/api/v1/pay/result/wxnotify");
            order.setProduct_id(shoppingItem.getSkuCode());
            order.setTrade_type("MWEB");
            if(StringUtils.equalsIgnoreCase(payVo.getAppType(), "iOS")){
                order.setScene_info("{\"h5_info\": {\"type\":\"IOS\",\"app_name\": \"小Q旅行\",\"bundle_id\": \"online.xiaoq\"}}");
            }else if(StringUtils.equalsIgnoreCase(payVo.getAppType(), "Android")){
                order.setScene_info("{\"h5_info\": {\"type\":\"Android\",\"app_name\": \"小Q旅行\",\"package_name\": \"com.tencent.tmgp.sgame\"}}");
            }else {
                return GenericResponse.ng("手机类型错误,为ios或android");
            }

            order.setSign(Signature.getSign(order.toMap(), key));

            UnifiedOrderService service = new UnifiedOrderService(certPath, certPassword);
            String result = service.request(order);
            Map<String, Object> map = XMLParser.getMapFromXML(result);
            String returnCode = (String) map.get("return_code");
            String err_code_des = (String) map.get("err_code_des");
            if (!StringUtils.isEmpty(returnCode) && StringUtils.equals(returnCode, "SUCCESS")
                    && StringUtils.isBlank(err_code_des)) {
                String mweb_url = (String) map.get("mweb_url");
                WxH5ReturnVo wxH5ReturnVo = new WxH5ReturnVo();
                wxH5ReturnVo.setMweb_url(mweb_url);
                return WxH5ReturnResponse.okWithData(wxH5ReturnVo);
            }

            if(StringUtils.isNotBlank(err_code_des)){
                return WxH5ReturnResponse.ng(err_code_des);
            }
            String return_msg = (String) map.get("return_msg");
            return WxH5ReturnResponse.ng(return_msg);
        } catch (Exception e) {
            LOGGER.error(e.getMessage(), e);
        }
        return PaySignResponse.ng("微信签名错误.");
    }


    public static String getIpAddr(HttpServletRequest request)
    {
        String ip = request.getHeader("X-Real-IP");
        if(!StringUtils.isBlank(ip) && !"unknown".equalsIgnoreCase(ip))
            return ip;
        ip = request.getHeader("X-Forwarded-For");
        if(!StringUtils.isBlank(ip) && !"unknown".equalsIgnoreCase(ip))
        {
            int index = ip.indexOf(',');
            if(index != -1)
                return ip.substring(0, index);
            else
                return ip;
        }
        if(ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip))
            ip = request.getHeader("Proxy-Client-IP");
        if(ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip))
            ip = request.getHeader("WL-Proxy-Client-IP");
        if(ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip))
            ip = request.getHeader("HTTP_CLIENT_IP");
        if(ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip))
            ip = request.getHeader("HTTP_X_FORWARDED_FOR");
        if(ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip))
            ip = request.getRemoteAddr();
        return ip;
    }

    /*@PostMapping(value = "/wx/h5PayTestsign", produces ={MediaType.APPLICATION_JSON_UTF8_VALUE})
    @ResponseBody
    public Object h5PayTest(HttpServletRequest req,
                                  HttpServletResponse response) {
        try {
            String nonce = "ls8o40lngs85pe9qvm3lccn2g4z9nk";
            String appId = "wx1f3ddeffce106844";
            String mchId = "1497234242";
            String key = "XiaoQtJ0lngs85pe9qvm3lccn2g4z9nk"; //
            String certPath = "D:\\weixin\\cert\\apiclient_cert.p12";
            String certPassword = "1497234242";

            String out_trade_no = RandomStringGenerator.getRandomStringByLength(10);

            UnifiedOrderReqData order = new UnifiedOrderReqData();
            order.setAppid(appId);
            order.setMch_id(mchId);
            order.setNonce_str(nonce);
            order.setBody("13241234");
            order.setOut_trade_no(out_trade_no);
            order.setTotal_fee(1);
            order.setSpbill_create_ip("1.202.219.75");
            order.setNotify_url("https://order.xiaoq.online/api/v1/pay/result/wxnotify");
            order.setTrade_type("MWEB");
            order.setProduct_id("223453");
            order.setScene_info("{\"h5_info\": {\"type\":\"IOS\",\"app_name\": \"小Q旅行\",\"bundle_id\": \"xiaoq.online\"}}");

            order.setSign(Signature.getSign(order.toMap(), key));

            UnifiedOrderService service = new UnifiedOrderService(certPath, certPassword);
            String result = service.request(order);
            System.out.println(result);
            Map<String, Object> map = XMLParser.getMapFromXML(result);
            String returnCode = (String) map.get("return_code");
            if (!StringUtils.isEmpty(returnCode)
                    && StringUtils.equals(returnCode, "SUCCESS")) {
                String url = (String) map.get("code_url");
                if (!StringUtils.isEmpty(url)) {
                    System.out.println("*****************************************" + url);
                }
            }

            System.out.println("******************************************");
            System.out.println("map: " + map);;
            System.out.println("******************************************");

            System.out.println("code is  " + returnCode);
            System.out.println("message is  " + (String) map.get("return_msg"));
            System.out.println("url is  " + (String) map.get("code_url"));
            System.out.println("err_code is  " + (String) map.get("err_code"));
            System.out.println("err_code_des  is  " + (String) map.get("err_code_des"));

//            if (!StringUtils.isEmpty(returnCode) && StringUtils.equals((String) map.get("return_msg"), "SUCCESS")
//                    || StringUtils.equals((String) map.get("return_msg"), "OK")) {
//                String prepay_id = (String) map.get("prepay_id");
//
//                Map<String, Object> signMap = new HashMap<String, Object>();
//
//                String nonceStr = RandomStringGenerator.getRandomStringByLength(10);
//                long currentMills = System.currentTimeMillis()/1000;
//                signMap.put("appid", appId);
//                signMap.put("partnerid", mchId);
//                signMap.put("package", "Sign=WXPay");
//                signMap.put("noncestr", nonceStr);
//                signMap.put("timestamp", currentMills);
//                signMap.put("prepayid", prepay_id);
//                String sign = Signature.getSign(signMap, key);
//
//                PaySignVo paySignVo = new PaySignVo();
//                paySignVo.setSign(sign);
//                paySignVo.setPrepayId(prepay_id);
//                paySignVo.setAppId(appId);
//                paySignVo.setPackageName("Sign=WXPay");
//                paySignVo.setPartnerId(mchId);
//                paySignVo.setTimestamp(currentMills);
//                paySignVo.setNonceStr(nonceStr);
//
//                return PaySignResponse.okWithData(paySignVo);
//            } else {
//                LOGGER.error("**********************************************request is failed");
//            }



            return map;
        } catch (Exception e) {
            LOGGER.error(e.getMessage(), e);
        }
        return "error";
    }*/






}
